home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / WarpQuake / Src / vid_ext.c < prev    next >
C/C++ Source or Header  |  2000-05-22  |  20KB  |  796 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. //
  21. // vid_ext.c: extended video modes
  22. // in this implementation, VESA-specific DOS video stuff
  23. //
  24.  
  25. // TODO: make dependencies on vid_vga.c explicit or eliminate them
  26.  
  27. #include <stdlib.h>
  28. #include <dos.h>
  29.  
  30. #include "quakedef.h"
  31. #include "d_local.h"
  32. #include "dosisms.h"
  33. #include "vid_dos.h"
  34. #include <dpmi.h>
  35.  
  36. #define MODE_SUPPORTED_IN_HW    0x0001
  37. #define COLOR_MODE                0x0008
  38. #define GRAPHICS_MODE            0x0010
  39. #define VGA_INCOMPATIBLE        0x0020
  40. #define LINEAR_FRAME_BUFFER        0x0080
  41.  
  42. #define LINEAR_MODE                0x4000
  43.  
  44. #define VESA_DONT_WAIT_VSYNC    0        // when page flipping
  45. #define VESA_WAIT_VSYNC            0x80
  46.  
  47. #define MAX_VESA_MODES            30    // we'll just take the first 30 if there
  48.                                     //  are more
  49. typedef struct {
  50.     int            pages[3];            // either 2 or 3 is valid
  51.     int            vesamode;            // LINEAR_MODE set if linear mode
  52.     void        *plinearmem;        // linear address of start of frame buffer
  53.     qboolean    vga_incompatible;
  54. } vesa_extra_t;
  55.  
  56. static vmode_t        vesa_modes[MAX_VESA_MODES] =
  57.     {{NULL, NULL, "    ********* VESA modes *********    "}};
  58. static vesa_extra_t    vesa_extra[MAX_VESA_MODES];
  59. static char            names[MAX_VESA_MODES][10];
  60.  
  61. extern regs_t regs;
  62.  
  63. static int        VID_currentpage;
  64. static int        VID_displayedpage;
  65. static int        *VID_pagelist;
  66. static byte        *VID_membase;
  67. static int        VID_banked;
  68.  
  69. typedef struct
  70. {
  71.     int modenum;
  72.     int mode_attributes;
  73.     int    winasegment;
  74.     int    winbsegment;
  75.     int    bytes_per_scanline; // bytes per logical scanline (+16)
  76.     int win; // window number (A=0, B=1)
  77.     int win_size; // window size (+6)
  78.     int granularity; // how finely i can set the window in vid mem (+4)
  79.     int width, height; // displayed width and height (+18, +20)
  80.     int bits_per_pixel; // er, better be 8, 15, 16, 24, or 32 (+25)
  81.     int bytes_per_pixel; // er, better be 1, 2, or 4
  82.     int memory_model; // and better be 4 or 6, packed or direct color (+27)
  83.     int num_pages; // number of complete frame buffer pages (+29)
  84.     int red_width; // the # of bits in the red component (+31)
  85.     int red_pos; // the bit position of the red component (+32)
  86.     int green_width; // etc.. (+33)
  87.     int green_pos; // (+34)
  88.     int blue_width; // (+35)
  89.     int blue_pos; // (+36)
  90.     int pptr;
  91.     int    pagesize;
  92.     int    numpages;
  93. } modeinfo_t;
  94.  
  95. static modeinfo_t modeinfo;
  96.  
  97. // all bytes to avoid problems with compiler field packing
  98. typedef struct vbeinfoblock_s {
  99.      byte            VbeSignature[4];
  100.      byte            VbeVersion[2];
  101.      byte            OemStringPtr[4];
  102.      byte            Capabilities[4];
  103.      byte            VideoModePtr[4];
  104.      byte            TotalMemory[2];
  105.      byte            OemSoftwareRev[2];
  106.      byte            OemVendorNamePtr[4];
  107.      byte            OemProductNamePtr[4];
  108.      byte            OemProductRevPtr[4];
  109.      byte            Reserved[222];
  110.      byte            OemData[256];
  111. } vbeinfoblock_t;
  112.  
  113. static int    totalvidmem;
  114. static byte    *ppal;
  115. qboolean    vsync_exists, de_exists;
  116.  
  117. qboolean VID_ExtraGetModeInfo(int modenum);
  118. int VID_ExtraInitMode (viddef_t *vid, vmode_t *pcurrentmode);
  119. void VID_ExtraSwapBuffers (viddef_t *vid, vmode_t *pcurrentmode,
  120.     vrect_t *rects);
  121.  
  122.  
  123. /*
  124. ================
  125. VGA_BankedBeginDirectRect
  126. ================
  127. */
  128. void VGA_BankedBeginDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode,
  129.     int x, int y, byte *pbitmap, int width, int height)
  130. {
  131.  
  132.     if (!lvid->direct)
  133.         return;
  134.  
  135.     regs.x.ax = 0x4f05;
  136.     regs.x.bx = 0;
  137.     regs.x.dx = VID_displayedpage;
  138.     dos_int86(0x10);
  139.  
  140.     VGA_BeginDirectRect (lvid, pcurrentmode, x, y, pbitmap, width, height);
  141.  
  142.     regs.x.ax = 0x4f05;
  143.     regs.x.bx = 0;
  144.     regs.x.dx = VID_currentpage;
  145.     dos_int86(0x10);
  146. }
  147.  
  148.  
  149. /*
  150. ================
  151. VGA_BankedEndDirectRect
  152. ================
  153. */
  154. void VGA_BankedEndDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode,
  155.     int x, int y, int width, int height)
  156. {
  157.  
  158.     if (!lvid->direct)
  159.         return;
  160.  
  161.     regs.x.ax = 0x4f05;
  162.     regs.x.bx = 0;
  163.     regs.x.dx = VID_displayedpage;
  164.     dos_int86(0x10);
  165.  
  166.     VGA_EndDirectRect (lvid, pcurrentmode, x, y, width, height);
  167.  
  168.     regs.x.ax = 0x4f05;
  169.     regs.x.bx = 0;
  170.     regs.x.dx = VID_currentpage;
  171.     dos_int86(0x10);
  172. }
  173.  
  174.  
  175. /*
  176. ================
  177. VID_SetVESAPalette
  178. ================
  179. */
  180. void VID_SetVESAPalette (viddef_t *lvid, vmode_t *pcurrentmode,
  181.     unsigned char *pal)
  182. {
  183.     int        i;
  184.     byte    *pp;
  185.  
  186.     UNUSED(lvid);
  187.     UNUSED(pcurrentmode);
  188.  
  189.     pp = ppal;
  190.  
  191.     for (i=0 ; i<256 ; i++)
  192.     {
  193.         pp[2] = pal[0] >> 2;
  194.         pp[1] = pal[1] >> 2;
  195.         pp[0] = pal[2] >> 2;
  196.         pp += 4;
  197.         pal += 3;
  198.     }
  199.  
  200.     regs.x.ax = 0x4F09;
  201.     regs.x.bx = 0;
  202.     regs.x.cx = 256;
  203.     regs.x.dx = 0;
  204.     regs.x.es = ptr2real(ppal) >> 4;
  205.     regs.x.di = ptr2real(ppal) & 0xf;
  206.     dos_int86(0x10);
  207.  
  208.     if (regs.x.ax != 0x4f)
  209.         Sys_Error ("Unable to load VESA palette\n");
  210. }
  211.  
  212.  
  213.  
  214.  
  215. /*
  216. ================
  217. VID_ExtraFarToLinear
  218. ================
  219. */
  220. void *VID_ExtraFarToLinear (void *ptr)
  221. {
  222.     int        temp;
  223.  
  224.     temp = (int)ptr;
  225.     return real2ptr(((temp & 0xFFFF0000) >> 12) + (temp & 0xFFFF));
  226. }
  227.  
  228.  
  229. /*
  230. ================
  231. VID_ExtraWaitDisplayEnable
  232. ================
  233. */
  234. void VID_ExtraWaitDisplayEnable ()
  235. {
  236.     while ((inportb (0x3DA) & 0x01) == 1)
  237.         ;
  238. }
  239.  
  240.  
  241. /*
  242. ================
  243. VID_ExtraVidLookForState
  244. ================
  245. */
  246. qboolean VID_ExtraVidLookForState (unsigned state, unsigned mask)
  247. {
  248.     int        i;
  249.     double    starttime, time;
  250.  
  251.     starttime = Sys_FloatTime ();
  252.  
  253.     do
  254.     {
  255.         for (i=0 ; i<100000 ; i++)
  256.         {
  257.             if ((inportb (0x3DA) & mask) == state)
  258.                 return true;
  259.         }
  260.  
  261.         time = Sys_FloatTime ();
  262.     } while ((time - starttime) < 0.1);
  263.  
  264.     return false;
  265. }
  266.  
  267.  
  268. /*
  269. ================
  270. VID_ExtraStateFound
  271. ================
  272. */
  273. qboolean VID_ExtraStateFound (unsigned state)
  274. {
  275.     int        i, workingstate;
  276.  
  277.     workingstate = 0;
  278.  
  279.     for (i=0 ; i<10 ; i++)
  280.     {
  281.         if (!VID_ExtraVidLookForState(workingstate, state))
  282.         {
  283.             return false;
  284.         }
  285.  
  286.         workingstate ^= state;
  287.     }
  288.  
  289.     return true;
  290. }
  291.  
  292.  
  293. /*
  294. ================
  295. VID_InitExtra
  296. ================
  297. */
  298. void VID_InitExtra (void)
  299. {
  300.     int                nummodes;
  301.     short            *pmodenums;
  302.     vbeinfoblock_t    *pinfoblock;
  303.     __dpmi_meminfo    phys_mem_info;
  304.  
  305.     pinfoblock = dos_getmemory(sizeof(vbeinfoblock_t));
  306.  
  307.     *(long *)pinfoblock->VbeSignature = 'V' + ('B'<<8) + ('E'<<16) + ('2'<<24);
  308.  
  309. // see if VESA support is available
  310.     regs.x.ax = 0x4f00;
  311.     regs.x.es = ptr2real(pinfoblock) >> 4;
  312.     regs.x.di = ptr2real(pinfoblock) & 0xf;
  313.     dos_int86(0x10);
  314.  
  315.     if (regs.x.ax != 0x4f)
  316.         return;        // no VESA support
  317.  
  318.     if (pinfoblock->VbeVersion[1] < 0x02)
  319.         return;        // not VESA 2.0 or greater
  320.  
  321.     Con_Printf ("VESA 2.0 compliant adapter:\n%s\n",
  322.                 VID_ExtraFarToLinear (*(byte **)&pinfoblock->OemStringPtr[0]));
  323.  
  324.     totalvidmem = *(unsigned short *)&pinfoblock->TotalMemory[0] << 16;
  325.  
  326.     pmodenums = (short *)
  327.             VID_ExtraFarToLinear (*(byte **)&pinfoblock->VideoModePtr[0]);
  328.  
  329. // find 8 bit modes until we either run out of space or run out of modes
  330.     nummodes = 0;
  331.  
  332.     while ((*pmodenums != -1) && (nummodes < MAX_VESA_MODES))
  333.     {
  334.         if (VID_ExtraGetModeInfo (*pmodenums))
  335.         {
  336.             vesa_modes[nummodes].pnext = &vesa_modes[nummodes+1];
  337.             if (modeinfo.width > 999)
  338.             {
  339.                 if (modeinfo.height > 999)
  340.                 {
  341.                     sprintf (&names[nummodes][0], "%4dx%4d", modeinfo.width,
  342.                              modeinfo.height);
  343.                     names[nummodes][9] = 0;
  344.                 }
  345.                 else
  346.                 {
  347.                     sprintf (&names[nummodes][0], "%4dx%3d", modeinfo.width,
  348.                              modeinfo.height);
  349.                     names[nummodes][8] = 0;
  350.                 }
  351.             }
  352.             else
  353.             {
  354.                 if (modeinfo.height > 999)
  355.                 {
  356.                     sprintf (&names[nummodes][0], "%3dx%4d", modeinfo.width,
  357.                              modeinfo.height);
  358.                     names[nummodes][8] = 0;
  359.                 }
  360.                 else
  361.                 {
  362.                     sprintf (&names[nummodes][0], "%3dx%3d", modeinfo.width,
  363.                              modeinfo.height);
  364.                     names[nummodes][7] = 0;
  365.                 }
  366.             }
  367.  
  368.             vesa_modes[nummodes].name = &names[nummodes][0];
  369.             vesa_modes[nummodes].width = modeinfo.width;
  370.             vesa_modes[nummodes].height = modeinfo.height;
  371.             vesa_modes[nummodes].aspect =
  372.                     ((float)modeinfo.height / (float)modeinfo.width) *
  373.                     (320.0 / 240.0);
  374.             vesa_modes[nummodes].rowbytes = modeinfo.bytes_per_scanline;
  375.             vesa_modes[nummodes].planar = 0;
  376.             vesa_modes[nummodes].pextradata = &vesa_extra[nummodes];
  377.             vesa_modes[nummodes].setmode = VID_ExtraInitMode;
  378.             vesa_modes[nummodes].swapbuffers = VID_ExtraSwapBuffers;
  379.             vesa_modes[nummodes].setpalette = VID_SetVESAPalette;
  380.  
  381.             if (modeinfo.mode_attributes & LINEAR_FRAME_BUFFER)
  382.             {
  383.             // add linear bit to mode for linear modes
  384.                 vesa_extra[nummodes].vesamode = modeinfo.modenum | LINEAR_MODE;
  385.                 vesa_extra[nummodes].pages[0] = 0;
  386.                 vesa_extra[nummodes].pages[1] = modeinfo.pagesize;
  387.                 vesa_extra[nummodes].pages[2] = modeinfo.pagesize * 2;
  388.                 vesa_modes[nummodes].numpages = modeinfo.numpages;
  389.  
  390.                 vesa_modes[nummodes].begindirectrect = VGA_BeginDirectRect;
  391.                 vesa_modes[nummodes].enddirectrect = VGA_EndDirectRect;
  392.  
  393.                 phys_mem_info.address = (int)modeinfo.pptr;
  394.                 phys_mem_info.size = 0x400000;
  395.  
  396.                 if (__dpmi_physical_address_mapping(&phys_mem_info))
  397.                     goto NextMode;
  398.  
  399.                 vesa_extra[nummodes].plinearmem =
  400.                          real2ptr (phys_mem_info.address);
  401.             }
  402.             else
  403.             {
  404.             // banked at 0xA0000
  405.                 vesa_extra[nummodes].vesamode = modeinfo.modenum;
  406.                 vesa_extra[nummodes].pages[0] = 0;
  407.                 vesa_extra[nummodes].plinearmem =
  408.                         real2ptr(modeinfo.winasegment<<4);
  409.  
  410.                 vesa_modes[nummodes].begindirectrect =
  411.                         VGA_BankedBeginDirectRect;
  412.                 vesa_modes[nummodes].enddirectrect = VGA_BankedEndDirectRect;
  413.                 vesa_extra[nummodes].pages[1] = modeinfo.pagesize;
  414.                 vesa_extra[nummodes].pages[2] = modeinfo.pagesize * 2;
  415.                 vesa_modes[nummodes].numpages = modeinfo.numpages;
  416.             }
  417.  
  418.             vesa_extra[nummodes].vga_incompatible =
  419.                     modeinfo.mode_attributes & VGA_INCOMPATIBLE;
  420.  
  421.             nummodes++;
  422.         }
  423. NextMode:
  424.         pmodenums++;
  425.     }
  426.  
  427. // add the VESA modes at the start of the mode list (if there are any)
  428.     if (nummodes)
  429.     {
  430.         vesa_modes[nummodes-1].pnext = pvidmodes;
  431.         pvidmodes = &vesa_modes[0];
  432.         numvidmodes += nummodes;
  433.         ppal = dos_getmemory(256*4);
  434.     }
  435.  
  436.     dos_freememory(pinfoblock);
  437. }
  438.  
  439.  
  440. /*
  441. ================
  442. VID_ExtraGetModeInfo
  443. ================
  444. */
  445. qboolean VID_ExtraGetModeInfo(int modenum)
  446. {
  447.     char    *infobuf;
  448.     int        numimagepages;
  449.  
  450.     infobuf = dos_getmemory(256);
  451.  
  452.     regs.x.ax = 0x4f01;
  453.     regs.x.cx = modenum;
  454.     regs.x.es = ptr2real(infobuf) >> 4;
  455.     regs.x.di = ptr2real(infobuf) & 0xf;
  456.     dos_int86(0x10);
  457.     if (regs.x.ax != 0x4f)
  458.     {
  459.         return false;
  460.     }
  461.     else
  462.     {
  463.         modeinfo.modenum = modenum;
  464.         modeinfo.bits_per_pixel = *(char*)(infobuf+25);
  465.         modeinfo.bytes_per_pixel = (modeinfo.bits_per_pixel+1)/8;
  466.         modeinfo.width = *(short*)(infobuf+18);
  467.         modeinfo.height = *(short*)(infobuf+20);
  468.  
  469.     // we do only 8-bpp in software
  470.         if ((modeinfo.bits_per_pixel != 8) ||
  471.             (modeinfo.bytes_per_pixel != 1) ||
  472.             (modeinfo.width > MAXWIDTH) ||
  473.             (modeinfo.height > MAXHEIGHT))
  474.         {
  475.             return false;
  476.         }
  477.  
  478.         modeinfo.mode_attributes = *(short*)infobuf;
  479.  
  480.     // we only want color graphics modes that are supported by the hardware
  481.         if ((modeinfo.mode_attributes &
  482.              (MODE_SUPPORTED_IN_HW | COLOR_MODE | GRAPHICS_MODE)) !=
  483.             (MODE_SUPPORTED_IN_HW | COLOR_MODE | GRAPHICS_MODE))
  484.         {
  485.             return false;
  486.         }
  487.  
  488.     // we only work with linear frame buffers, except for 320x200, which can
  489.     // effectively be linear when banked at 0xA000
  490.         if (!(modeinfo.mode_attributes & LINEAR_FRAME_BUFFER))
  491.         {
  492.             if ((modeinfo.width != 320) || (modeinfo.height != 200))
  493.                 return false;
  494.         }
  495.  
  496.         modeinfo.bytes_per_scanline = *(short*)(infobuf+16);
  497.  
  498.         modeinfo.pagesize = modeinfo.bytes_per_scanline * modeinfo.height;
  499.  
  500.         if (modeinfo.pagesize > totalvidmem)
  501.             return false;
  502.  
  503.     // force to one page if the adapter reports it doesn't support more pages
  504.     // than that, no matter how much memory it has--it may not have hardware
  505.     // support for page flipping
  506.         numimagepages = *(unsigned char *)(infobuf+29);
  507.  
  508.         if (numimagepages <= 0)
  509.         {
  510.         // wrong, but there seems to be an ATI VESA driver that reports 0
  511.             modeinfo.numpages = 1;
  512.         }
  513.         else if (numimagepages < 3)
  514.         {
  515.             modeinfo.numpages = numimagepages;
  516.         }
  517.         else
  518.         {
  519.             modeinfo.numpages = 3;
  520.         }
  521.  
  522.         if (*(char*)(infobuf+2) & 5)
  523.         {
  524.             modeinfo.winasegment = *(unsigned short*)(infobuf+8);
  525.             modeinfo.win = 0;
  526.         }
  527.         else if (*(char*)(infobuf+3) & 5)
  528.         {
  529.             modeinfo.winbsegment = *(unsigned short*)(infobuf+8);
  530.             modeinfo.win = 1;
  531.         }
  532.         modeinfo.granularity = *(short*)(infobuf+4) * 1024;
  533.         modeinfo.win_size = *(short*)(infobuf+6) * 1024;
  534.         modeinfo.bits_per_pixel = *(char*)(infobuf+25);
  535.         modeinfo.bytes_per_pixel = (modeinfo.bits_per_pixel+1)/8;
  536.         modeinfo.memory_model = *(unsigned char*)(infobuf+27);
  537.         modeinfo.num_pages = *(char*)(infobuf+29) + 1;
  538.  
  539.         modeinfo.red_width = *(char*)(infobuf+31);
  540.         modeinfo.red_pos = *(char*)(infobuf+32);
  541.         modeinfo.green_width = *(char*)(infobuf+33);
  542.         modeinfo.green_pos = *(char*)(infobuf+34);
  543.         modeinfo.blue_width = *(char*)(infobuf+35);
  544.         modeinfo.blue_pos = *(char*)(infobuf+36);
  545.  
  546.         modeinfo.pptr = *(long *)(infobuf+40);
  547.  
  548. #if 0
  549.         printf("VID: (VESA) info for mode 0x%x\n", modeinfo.modenum);
  550.         printf("  mode attrib = 0x%0x\n", modeinfo.mode_attributes);
  551.         printf("  win a attrib = 0x%0x\n", *(unsigned char*)(infobuf+2));
  552.         printf("  win b attrib = 0x%0x\n", *(unsigned char*)(infobuf+3));
  553.         printf("  win a seg 0x%0x\n", (int) modeinfo.winasegment);
  554.         printf("  win b seg 0x%0x\n", (int) modeinfo.winbsegment);
  555.         printf("  bytes per scanline = %d\n",
  556.                 modeinfo.bytes_per_scanline);
  557.         printf("  width = %d, height = %d\n", modeinfo.width,
  558.                 modeinfo.height);
  559.         printf("  win = %c\n", 'A' + modeinfo.win);
  560.         printf("  win granularity = %d\n", modeinfo.granularity);
  561.         printf("  win size = %d\n", modeinfo.win_size);
  562.         printf("  bits per pixel = %d\n", modeinfo.bits_per_pixel);
  563.         printf("  bytes per pixel = %d\n", modeinfo.bytes_per_pixel);
  564.         printf("  memory model = 0x%x\n", modeinfo.memory_model);
  565.         printf("  num pages = %d\n", modeinfo.num_pages);
  566.         printf("  red width = %d\n", modeinfo.red_width);
  567.         printf("  red pos = %d\n", modeinfo.red_pos);
  568.         printf("  green width = %d\n", modeinfo.green_width);
  569.         printf("  green pos = %d\n", modeinfo.green_pos);
  570.         printf("  blue width = %d\n", modeinfo.blue_width);
  571.         printf("  blue pos = %d\n", modeinfo.blue_pos);
  572.         printf("  phys mem = %x\n", modeinfo.pptr);
  573. #endif
  574.     }
  575.  
  576.     dos_freememory(infobuf);
  577.  
  578.     return true;
  579. }
  580.  
  581.  
  582. /*
  583. ================
  584. VID_ExtraInitMode
  585. ================
  586. */
  587. int VID_ExtraInitMode (viddef_t *lvid, vmode_t *pcurrentmode)
  588. {
  589.     vesa_extra_t    *pextra;
  590.     int                pageoffset;
  591.  
  592.     pextra = pcurrentmode->pextradata;
  593.  
  594.     if (vid_nopageflip.value)
  595.         lvid->numpages = 1;
  596.     else
  597.         lvid->numpages = pcurrentmode->numpages;
  598.  
  599. // clean up any old vid buffer lying around, alloc new if needed
  600.     if (!VGA_FreeAndAllocVidbuffer (lvid, lvid->numpages == 1))
  601.         return -1;    // memory alloc failed
  602.  
  603. // clear the screen and wait for the next frame. VGA_pcurmode, which
  604. // VGA_ClearVideoMem relies on, is guaranteed to be set because mode 0 is
  605. // always the first mode set in a session
  606.     if (VGA_pcurmode)
  607.         VGA_ClearVideoMem (VGA_pcurmode->planar);
  608.  
  609. // set the mode
  610.     regs.x.ax = 0x4f02;
  611.     regs.x.bx = pextra->vesamode;
  612.     dos_int86(0x10);
  613.  
  614.     if (regs.x.ax != 0x4f)
  615.         return 0;
  616.  
  617.     VID_banked = !(pextra->vesamode & LINEAR_MODE);
  618.     VID_membase = pextra->plinearmem;
  619.     VGA_width = lvid->width;
  620.     VGA_height = lvid->height;
  621.     VGA_rowbytes = lvid->rowbytes;
  622.  
  623.     lvid->colormap = host_colormap;
  624.  
  625.     VID_pagelist = &pextra->pages[0];
  626.  
  627. // wait for display enable by default only when triple-buffering on a VGA-
  628. // compatible machine that actually has a functioning display enable status
  629.     vsync_exists = VID_ExtraStateFound (0x08);
  630.     de_exists = VID_ExtraStateFound (0x01);
  631.  
  632.     if (!pextra->vga_incompatible  &&
  633.         (lvid->numpages == 3)      &&
  634.         de_exists                  &&
  635.         (_vid_wait_override.value == 0.0))
  636.     {
  637.         Cvar_SetValue ("vid_wait", (float)VID_WAIT_DISPLAY_ENABLE);
  638.  
  639.         VID_displayedpage = 0;
  640.         VID_currentpage = 1;
  641.     }
  642.     else
  643.     {
  644.         if ((lvid->numpages == 1) && (_vid_wait_override.value == 0.0))
  645.         {
  646.             Cvar_SetValue ("vid_wait", (float)VID_WAIT_NONE);
  647.             VID_displayedpage = VID_currentpage = 0;
  648.         }
  649.         else
  650.         {
  651.             Cvar_SetValue ("vid_wait", (float)VID_WAIT_VSYNC);
  652.  
  653.             VID_displayedpage = 0;
  654.  
  655.             if (lvid->numpages > 1)
  656.                 VID_currentpage = 1;
  657.             else
  658.                 VID_currentpage = 0;
  659.         }
  660.     }
  661.  
  662. // TODO: really should be a call to a function
  663.     pageoffset = VID_pagelist[VID_displayedpage];
  664.  
  665.     regs.x.ax = 0x4f07;
  666.     regs.x.bx = 0x80;    // wait for vsync so we know page 0 is visible
  667.     regs.x.cx = pageoffset % VGA_rowbytes;
  668.     regs.x.dx = pageoffset / VGA_rowbytes;
  669.     dos_int86(0x10);
  670.  
  671.     if (VID_banked)
  672.     {
  673.         regs.x.ax = 0x4f05;
  674.         regs.x.bx = 0;
  675.         regs.x.dx = VID_currentpage;
  676.         dos_int86(0x10);
  677.  
  678.         VGA_pagebase = VID_membase;
  679.     }
  680.     else
  681.     {
  682.         VGA_pagebase = VID_membase + VID_pagelist[VID_currentpage];
  683.     }
  684.  
  685.     if (lvid->numpages > 1)
  686.     {
  687.         lvid->buffer = VGA_pagebase;
  688.         lvid->conbuffer = lvid->buffer;
  689.     }
  690.     else
  691.     {
  692.         lvid->rowbytes = lvid->width;
  693.     }
  694.  
  695.     lvid->direct = VGA_pagebase;
  696.     lvid->conrowbytes = lvid->rowbytes;
  697.     lvid->conwidth = lvid->width;
  698.     lvid->conheight = lvid->height;
  699.  
  700.     lvid->maxwarpwidth = WARP_WIDTH;
  701.     lvid->maxwarpheight = WARP_HEIGHT;
  702.  
  703.     VGA_pcurmode = pcurrentmode;
  704.  
  705.     D_InitCaches (vid_surfcache, vid_surfcachesize);
  706.  
  707.     return 1;
  708. }
  709.  
  710.  
  711. /*
  712. ================
  713. VID_ExtraSwapBuffers
  714. ================
  715. */
  716. void VID_ExtraSwapBuffers (viddef_t *lvid, vmode_t *pcurrentmode,
  717.     vrect_t *rects)
  718. {
  719.     int    pageoffset;
  720.  
  721.     UNUSED(rects);
  722.     UNUSED(pcurrentmode);
  723.  
  724.     pageoffset = VID_pagelist[VID_currentpage];
  725.  
  726. // display the newly finished page
  727.     if (lvid->numpages > 1)
  728.     {
  729.     // page flipped
  730.         regs.x.ax = 0x4f07;
  731.     
  732.         if (vid_wait.value != VID_WAIT_VSYNC)
  733.         {
  734.             if ((vid_wait.value == VID_WAIT_DISPLAY_ENABLE) && de_exists)
  735.                 VID_ExtraWaitDisplayEnable ();
  736.     
  737.             regs.x.bx = VESA_DONT_WAIT_VSYNC;
  738.         }
  739.         else
  740.         {
  741.             regs.x.bx = VESA_WAIT_VSYNC;    // double buffered has to wait
  742.         }
  743.  
  744.         regs.x.cx = pageoffset % VGA_rowbytes;
  745.         regs.x.dx = pageoffset / VGA_rowbytes;
  746.         dos_int86(0x10);
  747.     
  748.         VID_displayedpage = VID_currentpage;
  749.         if (++VID_currentpage >= lvid->numpages)
  750.             VID_currentpage = 0;
  751.     
  752.     //
  753.     // set the new write window if this is a banked mode; otherwise, set the
  754.     // new address to which to write
  755.     //
  756.         if (VID_banked)
  757.         {
  758.             regs.x.ax = 0x4f05;
  759.             regs.x.bx = 0;
  760.             regs.x.dx = VID_currentpage;
  761.             dos_int86(0x10);
  762.         }
  763.         else
  764.         {
  765.             lvid->direct = lvid->buffer;    // direct drawing goes to the
  766.                                             //  currently displayed page
  767.             lvid->buffer = VID_membase + VID_pagelist[VID_currentpage];
  768.             lvid->conbuffer = lvid->buffer;
  769.         }
  770.     
  771.         VGA_pagebase = lvid->buffer;
  772.     }
  773.     else
  774.     {
  775.     // non-page-flipped
  776.         if (vsync_exists && (vid_wait.value == VID_WAIT_VSYNC))
  777.         {
  778.             VGA_WaitVsync ();
  779.         }
  780.  
  781.         while (rects)
  782.         {
  783.             VGA_UpdateLinearScreen (
  784.                     lvid->buffer + rects->x + (rects->y * lvid->rowbytes),
  785.                      VGA_pagebase + rects->x + (rects->y * VGA_rowbytes),
  786.                     rects->width,
  787.                     rects->height,
  788.                     lvid->rowbytes,
  789.                     VGA_rowbytes);
  790.  
  791.             rects = rects->pnext;
  792.         }
  793.     }
  794. }
  795.  
  796.